/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package elaborate.h2x.transform.position.schema.state;

import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import juixb.schema.SchemaNode;
import juixb.schema.SchemaTreeNode;
import juixb.schema.SequenceOperator;

/**
 *
 * @author lendle
 */
public class SequenceStateParser implements StateParser{

    public boolean isApplicable(SchemaNode schemaNode) {
        return schemaNode instanceof SequenceOperator;
    }
    /**
     * parse a SequenceOperator
     * a sequence operator represents a sequence of transition rules
     * @param parsers
     * @param schemaNode
     * @return 
     */
    public State parseState(StateParsers parsers, SchemaNode schemaNode) {
        SequenceOperator seq=(SequenceOperator) schemaNode;
        DefaultPseudoStateImpl state=new DefaultPseudoStateImpl();
        Enumeration<SchemaTreeNode> en=seq.children();
        State current=null;
        while(en.hasMoreElements()){
            SchemaNode child=(SchemaNode) en.nextElement();
            //System.out.println("\t"+child);
            State next=parsers.parseState(child);
            if(current!=null){
                for(State last : current.getLastSet()){
                    if(last instanceof ElementState){
                        for(State first : next.getFirstSet()){
                            if(first instanceof ElementState){
                                Transition transition=new Transition();
                                transition.setQName( ((ElementState)first).getElementNode().getQName() );
                                //System.out.println("\t\ttransition: "+((ElementState)last).getElementNode().getDisplayName()+":"+transition.getQName());
                                transition.setState(first);
                                 ((ElementState)last).addTransition(transition);
                            }
                        }
                    }
                }
            }
            state.addChildState(next);
            current=next;
        }
        state.setFirstSet(this.calculateFirstSet(state));
        state.setLastSet(this.calculateLastSet(state));
        return state;
    }
    
    protected Set<State> calculateFirstSet(PseudoState state){
        HashSet<State> set=new HashSet<State>();
        for(State childState : state.getChildStates()){
            if(childState instanceof PseudoState){
                PseudoState pseudoState=(PseudoState) childState;
                set.addAll(pseudoState.getFirstSet());
                if(pseudoState.getMin()>0){
                    //this child state is not optional
                    break;
                }
            }
            else{
                set.add(childState);
                break;
            }
        }
        return set;
        
    }
    
    protected Set<State> calculateLastSet(PseudoState state){
        HashSet<State> set=new HashSet<State>();
        List<State> childStates=state.getChildStates();
        for(int i=childStates.size()-1; i>=0; i--){
            State childState=childStates.get(i);
            if(childState instanceof PseudoState){
                PseudoState pseudoState=(PseudoState) childState;
                set.addAll(pseudoState.getLastSet());
                if(pseudoState.getMin()>0){
                    //this child state is not optional
                    break;
                }
            }
            else{
                set.add(childState);
                break;
            }
        }
        return set;
    }
}
